package fbc

import (
	"bytes"
	"context"
	"io"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

var currentDir string

func RunCode(c *gin.Context) {
	fileName, er := saveData(c)
	if er != nil {
		c.String(200, "Error save data:"+er.Error())
		return
	}

	// fileName := "D:\\code\\_fb\\fbc\\user\\src\\data\\2024\\09\\12\\e8367c7f-aed5-4556-b190-248e984324ca\\20240912012945"

	// log.Fatalln("cmd", fileName)
	//
	if err := makeExe(fileName, c); err == nil {
		runExec(fileName, c)
	}
	// var out2 bytes.Buffer
	// var stderr2 bytes.Buffer
	// fix := ""
	// if currentDir == "windows" {
	// 	fix = "exe"
	// }
	// exe := fileName + fix
	// cmd2 := exec.Command(exe)
	// cmd2.Stdout = &out2
	// cmd2.Stderr = &stderr2
	// // 运行命令并处理错误
	// // err = cmd2.Run()
	// // res = out2.String()
	// // if err != nil && err.Error() != "exit status 1" {
	// // 	res = "Error executing command:" + err.Error() + "\n" + res
	// // }
	// if res == "" {
	// 	res = "(No output)"
	// }
	// // cmd2.Process.Kill()
	// // 打印命令的输出
	// // log.Println("pid:", cmd2.Process.Pid)
	// c.String(200, res)
}

func makeExe(fileName string, c *gin.Context) error {
	var err error
	var res string
	// 创建一个命令，命令的每一个带空格的参数，都要分为一个独立的顺序传参，
	inc := "/fbc/libs/fbc/include"
	bas := fileName + ".bas"
	cmd := exec.Command("fbc", bas, "-i", inc)
	// 创建一个字节缓冲区来存储命令的输出
	var out bytes.Buffer
	var stderr bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &stderr
	// 运行命令并处理错误
	err = cmd.Run()
	res = out.String()
	if err != nil {
		res = "Error compile:" + err.Error() + "\n" + res
		c.String(200, res)
		return err
	}
	return nil
}
func runExec(fileName string, c *gin.Context) error {
	fix := ""
	if currentDir == "windows" {
		fix = "exe"
	}
	exe := fileName + fix
	ctx, cancel := context.WithTimeout(context.Background(), 55*time.Second)
	defer cancel()

	cmd := exec.CommandContext(ctx, exe)
	var out bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &out

	if err := cmd.Start(); err != nil {
		c.String(200, "Error starting command: "+err.Error())
		return err
	}

	// 等待命令完成或超时，
	//太好了，测试发现即使浏览器端刷新导致请求等待中断也能超时触发
	if err := cmd.Wait(); err != nil {
		if ctx.Err() == context.DeadlineExceeded {
			//是否需要结束？测试发现不kill也可以，但是保险还是kill一下
			cmd.Process.Kill()
			c.String(200, "Run code timed out")
		} else {
			c.String(200, "Error waiting for command:"+err.Error())
		}
	} else {
		c.String(200, out.String())
	}
	return nil
}

func saveData(c *gin.Context) (string, error) {
	// return "D:\\code\\_fb\\fbc\\user\\src\\data\\2024\\09\\12\\e8367c7f-aed5-4556-b190-248e984324ca\\20240912012945", nil

	// 获取当前日期
	now := time.Now()
	// 定义东八区时区
	// loc, err := time.LoadLocation("Asia/Shanghai")
	// if err != nil {
	// 	return "", err
	// }
	// 获取当前工作目录
	var err error
	currentDir, err = os.Getwd()
	if err != nil {
		return "", err
	}
	// 将 UTC 时间转换为东八区时间
	// nowInLoc := now.In(loc)
	// 格式化日期为年-月-日
	id := c.PostForm("myid")
	date := now.Format("2006/01/02")
	// 设置文件存储的目录
	dirPath := currentDir + "/data/" + date + "/" + id + "/"
	fileName := dirPath + now.Format("20060102150405")
	// 获取当前操作系统
	goos := runtime.GOOS
	if goos == "windows" {
		fileName = strings.Replace(fileName, "/", "\\", -1)
		fileName = strings.Replace(fileName, "\\", "\\\\", -1)
	}
	// 创建目录
	err = os.MkdirAll(dirPath, 0755)
	if err != nil {
		return "", err
	}
	// 定义文件路径

	// 打开文件，如果文件不存在则创建它，以读写模式打开
	file, err := os.OpenFile(fileName+".bas", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		return "", err
	}
	defer file.Close()

	// 要写入的数据
	data := c.PostForm("code")

	// 写入数据到文件
	_, err = io.WriteString(file, data)
	if err != nil {
		return "", err
	}

	// 也可以使用 io.Write 来写入数据
	// _, err = io.Write(file, []byte(data))
	// if err != nil {
	// 	log.Fatalf("error writing to file: %v", err)
	// }

	// log.Fatalln("fileName", fileName)
	return fileName, nil
}
